package com.niiwoo.civet.trade.service.dubbo.cardniu;

import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.dubbo.config.annotation.Service;
import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.trade.dao.entity.LendOrder;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectBorrowerSummary;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerPlanNewMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerSummaryMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dto.ProjectBorrowerPlanNewDTO;
import com.niiwoo.civet.trade.dto.common.CardNiuLoanResult;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerSummaryDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundStateDTO;
import com.niiwoo.civet.trade.dto.request.RefundWithholdRequestDTO;
import com.niiwoo.civet.trade.dto.request.cardniu.RepayApplyRequestDTO;
import com.niiwoo.civet.trade.dto.request.cardniu.RepayCalculateRequestDTO;
import com.niiwoo.civet.trade.dto.response.cardniu.RepayApplyResponseDTO;
import com.niiwoo.civet.trade.dto.response.cardniu.RepayCalculateResponseDTO;
import com.niiwoo.civet.trade.dto.response.cardniu.RepayPlanInfo;
import com.niiwoo.civet.trade.dto.response.cardniu.RepayResultDTO;
import com.niiwoo.civet.trade.service.cardniu.CardNiuRepaymentDubbpService;
import com.niiwoo.civet.trade.service.local.cardniu.CardNiuRefundLocalService;
import com.niiwoo.civet.trade.service.local.lend.ProjectLendLocalService;
import com.niiwoo.civet.trade.service.local.newRefund.dispatch.WithholdLocalService;
import com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core.FeeCalcForRefundService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.tripod.provider.exception.BizException;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @author yuanguang
 * @date 2018/02/10
 */
@Slf4j
@Service(version = "1.0.0", validation = "true")
public class CardNiuRefundDubboServiceImpl implements CardNiuRepaymentDubbpService {

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");

    @Autowired
    private ProjectMapperExt projectMapperExt;
    
    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapper;
    
    @Autowired
    private ProjectBorrowerPlanNewMapperExt projectBorrowerPlanNewMapper;
    
    @Autowired
    private ProjectLendLocalService projectLendLocalService;

    @Autowired
    private CardNiuRefundLocalService cardNiuRefundLocalService;
    
    @Autowired
    private FeeCalcForRefundService feeCalcForRefundService;

    @Autowired
    private ProjectLocalService projectLocalService;
    
    @Autowired
    private WithholdLocalService withholdLocalService;
    
    @Override
    public RepayCalculateResponseDTO repayCalculate(RepayCalculateRequestDTO requestDTO) {
        Assert.notNull(requestDTO.getProjectId(), "还款标的ID不能为空");
        Assert.notNull(requestDTO.getRepayType(), "还款请求类型不能为空");
        if (1 == requestDTO.getRepayType() && (null == requestDTO.getPeriods() || requestDTO.getPeriods().size() == 0)) {
        	throw new BizException("", "正常还款时，期数不能为空");
        }
        
        // 将卡牛的还款请求类型转换为交易中心对应的还款类型
        RefundTypeEnum refundTypeEnum = cardNiuRefundLocalService.transformTradeRefundType(requestDTO.getRepayType());
    	
        RepayCalculateResponseDTO repayCalculateResponseDTO = new RepayCalculateResponseDTO();
        
        Long projectId = requestDTO.getProjectId();
        
        // 标的信息
		Project project = Optional.ofNullable(projectMapperExt.selectByPrimaryKey(projectId)).orElseThrow(() -> new BizException("TRD20001"));
		
        // 调用还款计算服务计算待还金额
        RefundStateDTO refundStateDTO = null;
        if (RefundTypeEnum.IMMEDIATELY.equals(refundTypeEnum)) {
            refundStateDTO = feeCalcForRefundService.caculateAmountByPeriods(project.getProjectId(), requestDTO.getPeriods());
        } else {
        	refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(project.getProjectId(), refundTypeEnum);
        }
    	repayCalculateResponseDTO.setPrincipal(refundStateDTO.getCapital());
    	repayCalculateResponseDTO.setInterest(refundStateDTO.getInterest());
    	repayCalculateResponseDTO.setPenaltySum(refundStateDTO.getPenaltyFee());
    	repayCalculateResponseDTO.setPenaltyInterest(refundStateDTO.getPenaltyFee());
    	repayCalculateResponseDTO.setServiceCharge(refundStateDTO.getManageFee());
    	repayCalculateResponseDTO.setGuaranteeFee(refundStateDTO.getGuaranteeFee());
    	repayCalculateResponseDTO.setTotal(refundStateDTO.getAmount());
        
        // 还款后剩余待还本金
        if (RefundTypeEnum.OVERDEPT.equals(refundTypeEnum)) {
        	repayCalculateResponseDTO.setPrincipalUnfinished(BigDecimal.ZERO);
        } else {
			repayCalculateResponseDTO.setPrincipalUnfinished(cardNiuRefundLocalService.calculatePrincipalUnfinished(
					projectId, Collections.max(requestDTO.getPeriods())));
        }    	
        return repayCalculateResponseDTO;
    }

    @Override
    public RepayApplyResponseDTO repayApply(RepayApplyRequestDTO requestDTO) {
        RepayApplyResponseDTO repayApplyResponseDTO = new RepayApplyResponseDTO();
        
        Assert.notNull(requestDTO.getProjectId(), "还款标的ID不能为空");
        Assert.notNull(requestDTO.getRepayType(), "还款请求类型不能为空");
        
        // 将卡牛的还款请求类型转换为交易中心对应的还款类型
        RefundTypeEnum refundTypeEnum = cardNiuRefundLocalService.transformTradeRefundType(Integer.valueOf(requestDTO.getRepayType()));
        try {
            //调用代扣接口
            RefundWithholdRequestDTO refundWithholdRequestDTO = new RefundWithholdRequestDTO();
            refundWithholdRequestDTO.setProjectId(requestDTO.getProjectId());
            refundWithholdRequestDTO.setOrgRequestNo(requestDTO.getOrgRequestNo());
            refundWithholdRequestDTO.setRefundType(refundTypeEnum);
            refundWithholdRequestDTO.setTradeSource(RefundWithholdRequestDTO.WithHoldTradeSourceEnum.CARNIU);
            refundWithholdRequestDTO.setOptType(RefundWithholdRequestDTO.WithHoldOptTypeEnum.NORMAL);
            withholdLocalService.withhold(refundWithholdRequestDTO);
        	
        	repayApplyResponseDTO.setBatchRequestNo(null);
            repayApplyResponseDTO.setErrCode("0000");
            repayApplyResponseDTO.setSuccess(true);	
		} catch (Exception e) {
			if (e instanceof BizException) {
    			repayApplyResponseDTO.setErrCode("4102");
    			repayApplyResponseDTO.setMessage(((BizException) e).getMessage());				
			} else {
    			repayApplyResponseDTO.setErrCode("4102");
    			repayApplyResponseDTO.setMessage("系统异常");				
			}
		}
        return repayApplyResponseDTO;
    }

    @Override
    public RepayResultDTO queryRepayResult(Long projectId, String orgRequestNo) {
        return cardNiuRefundLocalService.queryRepayResult(projectId, orgRequestNo,null);
    }
    
    @Override
    public RepayResultDTO queryRepayResultByProjectId(Long projectId){
        return cardNiuRefundLocalService.queryRepayResultByProjectId(projectId);
    }
    
    @Override
    public List<RepayPlanInfo> queryRepayPlanInfo(Long projectId) {
		List<ProjectBorrowerPlanNewDTO> projectBorrowerPlanNewDTOList = Optional.ofNullable(projectBorrowerPlanNewMapper.selectByProjectIdForAmount(projectId))
				.orElseThrow(() -> new BizException("TRD20005"));
        ProjectBorrowerSummary summary = Optional.ofNullable(projectBorrowerSummaryMapper.selectByPrimaryKey(projectId))
                .orElseThrow(() -> new BizException("TRD20010"));    	
        return cardNiuRefundLocalService.queryRepayPlanInfo(projectBorrowerPlanNewDTOList, summary);
    }

    /**
     * 查询用户当前标的待还总金额
     *
     * @param projectId
     * @return
     */
    @Override
    public BigDecimal queryShouldRepayAmount(Long projectId) {
        return cardNiuRefundLocalService.queryShouldRepayAmount(projectId);
    }

    /**
     * 查询用户未还期数
     *
     * @param userId
     * @return
     */
    @Override
    public List<Integer> queryShouldRepayPeriods(String userId) {
        return cardNiuRefundLocalService.queryShouldRepayPeriods(userId);
    }

    /**
     * 查询还款摘要信息
     * @param projectId
     * @return
     */
    @Override
    public ProjectBorrowerSummaryDTO projectBorrowerSummary(Long projectId) {
        ProjectBorrowerSummary summary = projectBorrowerSummaryMapper.selectByPrimaryKey(projectId);
        ProjectBorrowerSummaryDTO projectBorrowerSummaryDTO = null;
        if (summary != null){
            projectBorrowerSummaryDTO = new ProjectBorrowerSummaryDTO();
            BeanUtils.copyProperties(summary, projectBorrowerSummaryDTO);
        }
        return projectBorrowerSummaryDTO;
    }

    /**
     * 卡牛借款成功后的数据
     * @param projectId
     * @return
     */
    @Override
    public CardNiuLoanResult getLoanAfterSuccess(Long projectId) {
        CardNiuLoanResult cardNiuLoanResult = new CardNiuLoanResult();

        try {
			ProjectDTO projectDTO = projectLocalService.selectProjectById(projectId);
            cardNiuLoanResult.setTotalLoan(projectDTO.getContractAmount());
            cardNiuLoanResult.setTotalPeriod(projectDTO.getDeadline());

            LendOrder lendOrder = projectLendLocalService.queryLendOrderByProjectId(projectId);
            if(lendOrder != null)
            cardNiuLoanResult.setLoanTime(simpleDateFormat.format(lendOrder.getSuccessTime()));      //放款时间

            ProjectBorrowerSummaryDTO projectBorrowerSummaryDTO = projectBorrowerSummary(projectId);
            cardNiuLoanResult.setRepayPlanVersionTime(simpleDateFormat.format(projectBorrowerSummaryDTO.getUpdateTime()));     //还款计划版本时间

            //还款计划
            List<RepayPlanInfo> repayPlanInfos = queryRepayPlanInfo(projectId);
            cardNiuLoanResult.setRepayPlanInfo(repayPlanInfos);
        } catch (Exception e) {
            log.error("getLoanAfterSuccess projectId:{} 异常:{}", projectId, e);
        }
        return cardNiuLoanResult;
    }
}
